﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OBUActivation
{
    /// <summary>
    /// 枚举类型，用来定义可操作的SAM卡的类型
    /// </summary>
    public enum SAM_TYPE
    {
        ESAM,PSAM,UNKN
    };

    /// <summary>
    /// 读卡器参数类，用来获取读卡器现在的参数状态
    /// </summary>
    public class ReaderSet
    {
        /// <summary>
        /// 读卡器环境句柄
        /// </summary>
        public int SCContextHandle;

        /// <summary>
        /// 读卡器名称
        /// </summary>
        public string SCReaderName;

        /// <summary>
        /// 连接实例句柄
        /// </summary>
        public int SCReaderHandle;

        /// <summary>
        /// 与之连接的卡的类型
        /// </summary>
        public SAM_TYPE SCCardType;

        /// <summary>
        /// 是否使用
        /// </summary>
        public bool SCIsUsed;

        /// <sumary>
        /// 构造函数
        /// </sumary>
        /// <param name="scContextHandle">读卡器环境句柄</param>
        /// <param name="scReaderName">读卡器名称</param>
        /// <param name="scReaderHandle">读卡器实例句柄</param>
        /// <param name="scCardType">与之连接的卡的类型</param>
        public ReaderSet(int scContextHandle, string scReaderName, int scReaderHandle, SAM_TYPE scCardType)
        {
            SCContextHandle = scContextHandle;
            SCReaderName = scReaderName;
            SCReaderHandle = scReaderHandle;
            SCIsUsed = false;
            SCCardType = scCardType;
        }
    }

    /// <sumary>
    /// SAM 卡参数工厂类
    /// 负责管理不同的ReaderSet,与操作类无关
    /// </sumary>
    public class SAMSetFactory
    {
        /// <summary>
        /// 私有静态对象实例
        /// </summary>
        private static SAMSetFactory m_SAMSetFactory = null;

        /// <summary>
        /// Esam卡片列表
        /// </summary>
        private static List<ReaderSet> m_EsamReader = new List<ReaderSet>();

        /// <summary>
        /// Psam卡片列表
        /// </summary>
        private static List<ReaderSet> m_PsamReader = new List<ReaderSet>();

        /// <summary>
        /// 未知类型卡片列表
        /// </summary>
        private static List<ReaderSet> m_UnknReader = new List<ReaderSet>();

        /// <summary>
        /// 读卡器环境句柄
        /// </summary>
        private static int m_Context = -1;

        /// <summary>
        /// 私有构造函数
        /// </summary>
        private SAMSetFactory()
        {
            // 获取读卡器列表
            List<string> names = SCDriver.SCardListReaders(m_Context);
            for (int i = 0; i < names.Count; i++)
            {
                int reader = -1, protocol = 0;
                int result = SCDriver.SCardConnect(m_Context, names[i], 1, 1, ref reader, ref protocol);
                if (result != 0)
                {
                    continue;
                }
                byte[] switchCard = { 0X00, 0X70, 0X11, 0X10 };
                byte[] readSCType = { 0X80, 0X74, 0X00, 0X00, 0X04 };
                SCARD_IO_REQUEST request;
                request.m_Ptl = 0;
                request.m_PcL = 8;
                int rspLength = 255;byte[] rspBuffer = new byte[rspLength];
                result = SCDriver.SCardTransmit(reader, ref request, switchCard, switchCard.Length, ref request, ref rspBuffer[0], ref rspLength);
                rspLength = 255;
                result = SCDriver.SCardTransmit(reader, ref request, readSCType, readSCType.Length, ref request, ref rspBuffer[0], ref rspLength);
                if (result == 0)
                {
                    if (rspBuffer[3] == 1 || rspBuffer[3] == 4)
                    {
                        ReaderSet set = new ReaderSet(m_Context, names[i], reader, SAM_TYPE.ESAM);
                        m_EsamReader.Add(set);
                    }
                    else if (rspBuffer[3] == 2 || rspBuffer[3] == 3)
                    {
                        ReaderSet set = new ReaderSet(m_Context, names[i], reader, SAM_TYPE.PSAM);
                        m_PsamReader.Add(set);
                    }
                    else
                    {
                        ReaderSet set = new ReaderSet(m_Context, names[i], reader, SAM_TYPE.UNKN);
                        m_UnknReader.Add(set);
                    }
                }
                else
                {
                    ReaderSet set = new ReaderSet(m_Context, names[i], reader, SAM_TYPE.UNKN);
                    m_UnknReader.Add(set);
                }
                SCDriver.SCardDisconnect(reader, 0);
            }
        }

        /// <summary>
        /// 初始化读卡器环境
        /// </summary>
        /// <returns></returns>
        public static bool Init()
        {
            int result = SCDriver.SCardEstablishContext(0, 0, 0, out m_Context);
            if (result != 0)
            {
                return false;
            }
            return true;
        }

        /// <sumary>
        /// 获取工厂实例
        /// </sumary>
        /// <returns>工厂实例</returns>
        public static SAMSetFactory GetInstance()
        {
            if (m_SAMSetFactory == null)
            {
                m_SAMSetFactory = new SAMSetFactory();
            }
            return m_SAMSetFactory;
        }

        /// <summary>
        /// 关闭读卡器环境句柄
        /// </summary>
        public static void Destroy()
        {
            SCDriver.SCardReleaseContext(m_Context);
        }

        /// <sumary>
        /// 获取配置参数实例
        /// </sumary>
        /// <param name="type">卡型</param>
        /// <returns>对应卡型的参数实例</returns>
        public ReaderSet Get(SAM_TYPE type)
        {
            switch (type)
            {
                case SAM_TYPE.ESAM:
                    for (int i = 0; i < m_EsamReader.Count; ++i)
                    {
                        if (!m_EsamReader[i].SCIsUsed)
                        {
                            m_EsamReader[i].SCIsUsed = true; return m_EsamReader[i];
                        }
                    }
                    break;
                case SAM_TYPE.PSAM:
                    for (int i = 0; i < m_PsamReader.Count; ++i)
                    {
                        if (!m_PsamReader[i].SCIsUsed)
                        {
                            m_PsamReader[i].SCIsUsed = true; return m_PsamReader[i];
                        }
                    }
                    break;
                case SAM_TYPE.UNKN:
                    for (int i = 0; i < m_UnknReader.Count; ++i)
                    {
                        if (!m_UnknReader[i].SCIsUsed)
                        {
                            m_UnknReader[i].SCIsUsed = true; return m_UnknReader[i];
                        }
                    }
                    break;
            }
            return null;
        }
    }

    /// <summary>
    /// SAM卡操作基类
    /// </summary>
    public class SAMReader
    {
        /// <summary>
        /// 读卡器设置
        /// </summary>
        protected ReaderSet m_Set = null;

        /// <summary>
        /// 读卡器是否打开
        /// </summary>
        private bool m_IsOpen = false;

        /// <summary>
        /// 打开读卡器
        /// </summary>
        /// <param name="set"></param>
        /// <returns></returns>
        public virtual bool Open(ReaderSet set)
        {
            return true;
        }

        /// <summary>
        /// SAM卡复位
        /// </summary>
        /// <returns></returns>
        public byte[] Reset()
        {
            byte[] cmd = { 0XFE, 0XFE, 0XFE, 0XFE, 0X00 };
            return SendCommand(cmd);
        }

        /// <summary>
        /// 关闭读卡器
        /// </summary>
        /// <returns>关闭成功返回 true，反之返回 false</returns>
        public bool Close()
        {
            if (m_IsOpen && 0 == SCDriver.SCardDisconnect(m_Set.SCReaderHandle, 0))
            {
                m_IsOpen = false;
                return true;
            }
            return false;
        }

        /// <sumary>
        /// SAM 卡发送命令
        /// </sumary>
        /// <param name="data">发送的命令数据</param>
        /// <returns>返回的应答数据</returns>
        public byte[] SendCommand(byte[] data)
        {
            // 设置通信规约
            SCARD_IO_REQUEST request;
            request.m_Ptl = 0;
            request.m_PcL = 8;
            // 发送命令
            int rspLength = 1024;
            byte[] rspBuffer = new byte[rspLength];
            int result = SCDriver.SCardTransmit(m_Set.SCReaderHandle, ref request, data, data.Length, ref request, ref rspBuffer[0], ref rspLength);
            if (result != 0)
            {
                return null;
            }
            // 应答命令
            if (rspBuffer[0] == 0X61)
            {
                rspLength = 1024;
                byte[] getResponse = { 0X00, 0XC0, 0X00, 0X00, rspBuffer[1] };
                result = SCDriver.SCardTransmit(m_Set.SCReaderHandle, ref request, getResponse, getResponse.Length, ref request, ref rspBuffer[0], ref rspLength);
                if (result != 0)
                {
                    return null;
                }
            }
            // 应答
            byte[] response = new byte[rspLength];
            Array.Copy(rspBuffer, response, rspLength);
            return response;
        }
    }

    /// <sumary>
    /// ESAM 卡操作类
    /// </sumary>
    public class ESAMReader:SAMReader
    {
        /// <sumary>
        /// 打开读卡器
        /// </sumary>
        /// <param name="set">读卡器配置参数</param>
        /// <returns>打开成功返回 true，反之返回 false</returns>
        public override bool Open(ReaderSet set)
        {
            if (set.SCCardType != SAM_TYPE.ESAM)
            {
                return false;
            }
            m_Set = set;
            int reader = -1, protocol = 0;
            if (0 != SCDriver.SCardConnect(m_Set.SCContextHandle, m_Set.SCReaderName, 1, 1, ref reader, ref protocol))
            {
                return false;
            }
            m_Set.SCReaderHandle = reader;
            return true;
        }
    }

    /// <sumary>
    /// PSAM 卡操作类
    /// </sumary>
    public class PSAMReader:SAMReader
    {
        /// <sumary>
        /// 打开读卡器
        /// </sumary>
        /// <param name="set">读卡器配置参数</param>
        /// <returns>打开成功返回 true，反之返回 false</returns>
        public override bool Open(ReaderSet set)
        {
            if (set.SCCardType != SAM_TYPE.PSAM)
            {
                return false;
            }
            m_Set = set;
            int reader = -1, protocol = 0;
            if (0 != SCDriver.SCardConnect(m_Set.SCContextHandle, m_Set.SCReaderName, 1, 1, ref reader, ref protocol))
            {
                return false;
            }
            m_Set.SCReaderHandle = reader;
            return true;
        }
    }

    /// <sumary>
    /// PSAM 卡操作类
    /// </sumary>
    public class UNKNReader:SAMReader
    {
        /// <sumary>
        /// 打开读卡器
        /// </sumary>
        /// <param name="set">读卡器配置参数</param>
        /// <returns>打开成功返回 true，反之返回 false</returns>
        public override bool Open(ReaderSet set)
        {
            if (set.SCCardType != SAM_TYPE.UNKN)
            {
                return false;
            }
            m_Set = set;
            int reader = -1, protocol = 0;
            if (0 != SCDriver.SCardConnect(m_Set.SCContextHandle, m_Set.SCReaderName, 1, 1, ref reader, ref protocol))
            {
                return false;
            }
            m_Set.SCReaderHandle = reader;
            return true;
        }
    }
}
